package org.ns.tomdog.server.support;

import org.ns.tomdog.server.RequestParseException;
import org.ns.tomdog.server.ServerRequest;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 服务请求实现
 */
public class ServerRequestImpl implements ServerRequest {
    private RequestInputStream inputStream;
    private String method;
    private String version;
    private String url;
    private String queryString;
    private Map<String, List<String>> headers;
    public ServerRequestImpl(InputStream inputStream) throws RequestParseException {
        parse(inputStream);
    }

    private void parse(InputStream inputStream) throws RequestParseException {
        try {

            List<byte[]> readList = new ArrayList<>(); // 每一行
            byte[] bytes = new byte[1024];
            int len = 0;
            ByteArrayOutputStream bytebuffer = new ByteArrayOutputStream(1024);
            int residue = 0;
            X:while ((len = inputStream.read(bytes)) != -1) {
                for (int i = 0; i < len; i++) {
                    byte b = bytes[i];
                    if (b == (byte)'\r') {

                    } else if (b == (byte) '\n') { // 截断
                        byte[] linebytes = bytebuffer.toByteArray();
                        bytebuffer.reset();
                        if (linebytes.length == 0) {
                            residue = len - (i + 1);
                            break X;
                        }
                        readList.add(linebytes);
                    } else {
                        bytebuffer.write(b);
                    }
                }

            }
            if (residue > 0) {
                byte[] cachebytes = new byte[residue];
                System.arraycopy(bytes, len - residue, cachebytes, 0, residue);
                RequestInputStream requestInputStream = new RequestInputStream(cachebytes, inputStream);
                this.inputStream = requestInputStream;
            }
            parse0(readList.get(0));
            parse1(readList);
        } catch (Exception e) {
            throw new RequestParseException(e);
        }
    }

    private void parse0(byte[] bytes) {
        String text = new String(bytes, Charset.forName("UTF-8"));
        String values[] = text.split("\\ ");
        this.method = values[0];
        String urlformat = values[1];
        parseUrl(urlformat);
        this.version = values[2].trim();

    }
    private void parseUrl(String urlformat) {
        int index = urlformat.indexOf("?");
        if (index == -1) {
            this.url = urlformat;
        } else {
            this.url = urlformat.substring(0, index);
            this.queryString = urlformat.substring(index + 1);
        }
    }

    private void parse1(List<byte[]> bytesList) {
        Map<String, List<String>> map = new HashMap<>();
        for (int i = 1; i < bytesList.size(); i++) {
            byte[] bytes = bytesList.get(i);
            String text = new String(bytes, Charset.forName("UTF-8"));
            int index = text.indexOf(":");
            if (index != -1) {
                String key = text.substring(0, index);
                String val = text.substring(index + 1);
                List<String> list = map.get(key);
                if (list == null) {
                    list = new ArrayList<>();
                    map.put(key, list);
                }
                list.add(val);
            }
        }
        this.headers = map;
    }

    @Override
    public String getMethod() {
        return method;
    }

    @Override
    public String getVersion() {
        return version;
    }

    @Override
    public String getUrl() {
        return url;
    }

    @Override
    public Map<String, List<String>> getHeaders() {
        return headers;
    }

    @Override
    public String getHeader(String name) {
        List<String> list = headers.get(name);
        if (list == null || list.size() == 0) {
            return null;
        }
        return list.get(0);
    }

    @Override
    public String getQueryString() {
        return queryString;
    }

    @Override
    public InputStream getInputStream() {
        return inputStream;
    }
}
